1   /*
2    * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  package com.sun.jmx.mbeanserver;
27  
28  import java.lang.reflect.InvocationTargetException;
29  import java.lang.reflect.Method;
30  import java.lang.reflect.Type;
31  import java.util.WeakHashMap;
32  import javax.management.Descriptor;
33  import javax.management.ImmutableDescriptor;
34  import javax.management.IntrospectionException;
35  import javax.management.MBeanAttributeInfo;
36  import javax.management.MBeanException;
37  import javax.management.MBeanOperationInfo;
38  import javax.management.NotCompliantMBeanException;
39  import javax.management.NotificationBroadcaster;
40  import javax.management.NotificationBroadcasterSupport;
41  
42  /**
43   * @since 1.6
44   */
45  class StandardMBeanIntrospector extends MBeanIntrospector<Method> {
46      private static final StandardMBeanIntrospector instance =
47          new StandardMBeanIntrospector();
48  
49      static StandardMBeanIntrospector getInstance() {
50          return instance;
51      }
52  
53      @Override
54      PerInterfaceMap<Method> getPerInterfaceMap() {
55          return perInterfaceMap;
56      }
57  
58      @Override
59      MBeanInfoMap getMBeanInfoMap() {
60          return mbeanInfoMap;
61      }
62  
63      @Override
64      MBeanAnalyzer<Method> getAnalyzer(Class<?> mbeanInterface)
65              throws NotCompliantMBeanException {
66          return MBeanAnalyzer.analyzer(mbeanInterface, this);
67      }
68  
69      @Override
70      boolean isMXBean() {
71          return false;
72      }
73  
74      @Override
75      Method mFrom(Method m) {
76          return m;
77      }
78  
79      @Override
80      String getName(Method m) {
81          return m.getName();
82      }
83  
84      @Override
85      Type getGenericReturnType(Method m) {
86          return m.getGenericReturnType();
87      }
88  
89      @Override
90      Type[] getGenericParameterTypes(Method m) {
91          return m.getGenericParameterTypes();
92      }
93  
94      @Override
95      String[] getSignature(Method m) {
96          Class<?>[] params = m.getParameterTypes();
97          String[] sig = new String[params.length];
98          for (int i = 0; i < params.length; i++)
99              sig[i] = params[i].getName();
100         return sig;
101     }
102 
103     @Override
104     void checkMethod(Method m) {
105     }
106 
107     @Override
108     Object invokeM2(Method m, Object target, Object[] args, Object cookie)
109             throws InvocationTargetException, IllegalAccessException,
110                    MBeanException {
111         return m.invoke(target, args);
112     }
113 
114     @Override
115     boolean validParameter(Method m, Object value, int paramNo, Object cookie) {
116         return isValidParameter(m, value, paramNo);
117     }
118 
119     @Override
120     MBeanAttributeInfo getMBeanAttributeInfo(String attributeName,
121             Method getter, Method setter) {
122 
123         final String description = "Attribute exposed for management";
124         try {
125             return new MBeanAttributeInfo(attributeName, description,
126                                           getter, setter);
127         } catch (IntrospectionException e) {
128             throw new RuntimeException(e); // should not happen
129         }
130     }
131 
132     @Override
133     MBeanOperationInfo getMBeanOperationInfo(String operationName,
134             Method operation) {
135         final String description = "Operation exposed for management";
136         return new MBeanOperationInfo(description, operation);
137     }
138 
139     @Override
140     Descriptor getBasicMBeanDescriptor() {
141         /* We don't bother saying mxbean=false, and we can't know whether
142            the info is immutable until we know whether the MBean class
143            (not interface) is a NotificationBroadcaster. */
144         return ImmutableDescriptor.EMPTY_DESCRIPTOR;
145     }
146 
147     @Override
148     Descriptor getMBeanDescriptor(Class<?> resourceClass) {
149         boolean immutable = isDefinitelyImmutableInfo(resourceClass);
150         return new ImmutableDescriptor("mxbean=false",
151                                        "immutableInfo=" + immutable);
152     }
153 
154     /* Return true if and only if we can be sure that the given MBean implementation
155      * class has immutable MBeanInfo.  A Standard MBean that is a
156      * NotificationBroadcaster is allowed to return different values at
157      * different times from its getNotificationInfo() method, which is when
158      * we might not know if it is immutable.  But if it is a subclass of
159      * NotificationBroadcasterSupport and does not override
160      * getNotificationInfo(), then we know it won't change.
161      */
162     static boolean isDefinitelyImmutableInfo(Class<?> implClass) {
163         if (!NotificationBroadcaster.class.isAssignableFrom(implClass))
164             return true;
165         synchronized (definitelyImmutable) {
166             Boolean immutable = definitelyImmutable.get(implClass);
167             if (immutable == null) {
168                 final Class<NotificationBroadcasterSupport> nbs =
169                         NotificationBroadcasterSupport.class;
170                 if (nbs.isAssignableFrom(implClass)) {
171                     try {
172                         Method m = implClass.getMethod("getNotificationInfo");
173                         immutable = (m.getDeclaringClass() == nbs);
174                     } catch (Exception e) {
175                         // Too bad, we'll say no for now.
176                         return false;
177                     }
178                 } else
179                     immutable = false;
180                 definitelyImmutable.put(implClass, immutable);
181             }
182             return immutable;
183         }
184     }
185     private static final WeakHashMap<Class<?>, Boolean> definitelyImmutable =
186             new WeakHashMap<Class<?>, Boolean>();
187 
188     private static final PerInterfaceMap<Method>
189         perInterfaceMap = new PerInterfaceMap<Method>();
190 
191     private static final MBeanInfoMap mbeanInfoMap = new MBeanInfoMap();
192 }